package com.simple.jdbc.core.sqlSession;

import com.simple.jdbc.core.executor.Executor;
import com.simple.jdbc.core.pojo.Configuration;
import com.simple.jdbc.core.pojo.MappedStatement;

import java.lang.reflect.*;
import java.util.List;

public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    private Executor executor;

    public DefaultSqlSession(Configuration configuration, Executor executor) {
        this.configuration = configuration;
        this.executor = executor;
    }

    @Override
    public <E> List<E> selectList(String statementId, Object param) {
        //查询操作委派给执行器
        //query（） 执行jdbc
        // 1 库配置信息  2 sql配置信息
        MappedStatement mappedStatement = configuration.getMappedStatementByStatementId(statementId);
        List<E> list = null;
        try {
            list = executor.query(configuration,mappedStatement,param);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return list;
    }

    @Override
    public <T> T selectOne(String statementId, Object param) {

        List<Object> list = this.selectList(statementId,param);
        if (list.size() == 1) {
            return (T) list.get(0);
        } else if (list.size() > 1){
            throw new RuntimeException("返回结果过多");
        }else {
            return null;
        }
    }

    @Override
    public void close() {
        executor.close();
    }

    @Override
    public <T> T getMapper(Class<?> mapperClass) {

        //jdk动态代理生成基于接口代理对象
        Object proxy = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                //数据库 操作jdbc

                //获取statementId
                /**
                 * 设计规范
                 * 接口全路径和namespace保持一致
                 * 方法名要和id保持一致
                 */
                String methodName = method.getName();
                String interfaceName = method.getDeclaringClass().getName();

                String statementId = interfaceName + "." + methodName;

                //确定调用方法  根据sqlCommandType
                MappedStatement mappedStatement = configuration.getMappedStatementByStatementId(statementId);
                //select update delete insert
                //todo 目前写死 select
                String sqlCommandType = mappedStatement.getSqlCommandType();

                switch (sqlCommandType){
                    case "select":
                        //确定调用select相关的哪个方法
                        Type genericReturnType = method.getGenericReturnType();
                        //是否实现泛型类型参数化  判断是否包含泛型
                        if (genericReturnType instanceof ParameterizedType){
                            if (args != null) {
                                return selectList(statementId,args[0]);
                            }
                            return selectList(statementId,null);
                        }
                        return selectOne(statementId,args[0]);
                    case "update":
                        break;
                }
                return null;
            }
        });

        return (T)proxy;
    }
}
